package qmlt.learning.knn;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import qmlt.dataset.Attribute;
import qmlt.dataset.DataSet;
import qmlt.dataset.Instance;
import qmlt.dataset.utils.ListUtils;
import qmlt.learning.Learner;
import qmlt.learning.knn.control.KNNController;

public class KNN implements Learner<KNNController>
{

	protected class Item implements Comparable<Item>
	{
		public Instance	instance;

		public float		distance;

		public int			correct		= 0;

		public int			incorrect	= 0;

		@Override
		public int compareTo(Item other)
		{
			return Float.compare(distance, other.distance);
		}
	}

	protected KNNController	controller;

	protected List<Item>					items	= new ArrayList<Item>();

	public void feedAnInstance(Instance inst)
	{
		Item item = new Item();
		item.instance = inst;
		items.add(item);
	}

	@Override
	public Object predict(Instance instance)
	{
		for (Item item : items)
		{
			float distance = controller.getDistance(instance, item.instance);
			item.distance = distance;
		}

		Collections.sort(items);

		int k = controller.getK();
		if (k == 1)
		{
			return items.get(0).instance.getTarget();
		}
		// else: k > 1
		List<Object> preds = new ArrayList<Object>();
		for (int i = 0; i < k; ++i)
		{
			Item item = items.get(i);
			preds.add(item.instance.getTarget());
		}
		if (instance.dataSet.getTargetDef().type.equals(Attribute.STRING))
		{
			return ListUtils.findMajor(preds);
		}
		else
		// FLOAT
		{
			List<Number> values = ListUtils.convert(preds);
			return ListUtils.mean(values);
		}
	}

	@Override
	public void train(DataSet trainSet, KNNController controller)
	{
		this.controller = controller;
		for (Instance inst : trainSet.getInstances())
		{
			feedAnInstance(inst);
		}
	}

	@Override
	public void loadModel(String inputFilepath)
	{
		// TODO Auto-generated method stub

	}

	@Override
	public void saveModel(String outputFilepath)
	{
		// TODO Auto-generated method stub

	}

}
